package com.hczt.xhminiapp.adminapi.modules.system.service;

import com.hczt.xhminiapp.adminapi.conf.security.SecurityUtils;
import com.hczt.xhminiapp.adminapi.modules.system.vo.AllotRole;
import com.hczt.xhminiapp.adminapi.modules.system.vo.ChangePassword;
import com.hczt.xhminiapp.adminapi.modules.system.vo.SysUserInfo;
import com.hczt.xhminiapp.adminapi.modules.system.vo.SysUserQuery;
import com.hczt.xhminiapp.common.bean.CodeMsg;
import com.hczt.xhminiapp.common.exception.BizException;
import com.hczt.xhminiapp.common.utils.MD5Util;
import com.hczt.xhminiapp.db.entity.SysPermission;
import com.hczt.xhminiapp.db.entity.SysRole;
import com.hczt.xhminiapp.db.entity.SysUser;
import com.hczt.xhminiapp.db.entity.SysUser_;
import com.hczt.xhminiapp.db.repository.SysRoleRepository;
import com.hczt.xhminiapp.db.repository.SysUserRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 红创-马海强
 * @date 2019-03-13 14:35
 * @description 系统用户业务处理
 */
@Service
public class SysUserService {

    @Resource
    private SysUserRepository sysUserRepository;
    @Resource
    private SysRoleRepository sysRoleRepository;
    @Resource
    private SysPermissionService sysPermissionService;

    private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    /**
     * 分页查找用户
     *
     * @return
     */
    public Page<SysUser> findSysUsers(SysUserQuery query, Pageable page) {
        Pageable pageable = new PageRequest(page.getPageNumber(), page.getPageSize(), new Sort(Sort.Direction.DESC, "createTime"));
        return sysUserRepository.findAll(build(query), pageable);
    }

    private Specification<SysUser> build(SysUserQuery query) {
        return (root, criteriaQuery, builder) -> {
            Predicate predicate = builder.conjunction();
            if (query.getEnable() != null) {
                predicate = builder.and(predicate, builder.equal(root.get(SysUser_.enabled), query.getEnable()));
            }
            if (!StringUtils.isEmpty(query.getSearch())) {
                String search = "%" + query.getSearch() + "%";
                Predicate likeUserName = builder.like(root.get(SysUser_.username), search);
                Predicate likeRealName = builder.like(root.get(SysUser_.realName), search);
                predicate = builder.and(predicate, builder.or(likeUserName, likeRealName));
            }
//            predicate = builder.and(predicate, builder.equal(root.get(SysUser_.isSystem), false));
            return predicate;
        };
    }

    /**
     * 添加用户
     * @param sysUser
     * @throws BizException
     */
    @Transactional
    public void save(SysUser sysUser) throws BizException {
        if(isExistSysUser(sysUser.getUsername())){
            throw new BizException(CodeMsg.USER_EXISTS);
        }
        setPassword(sysUser, sysUser.getPassword());
        sysUser.setCreateTime(new Date());
        sysUserRepository.save(sysUser);
    }

    private boolean isExistSysUser(String username) {
        return sysUserRepository.findByUsername(username) != null;
    }

    /**
     * 更新用户
     * @param userInfo
     * @throws BizException
     */
    @Transactional
    public void update(SysUser userInfo) throws Exception {
        if(isExistSysUser(userInfo.getUsername(), userInfo.getUserId())){
            throw new BizException(CodeMsg.USER_EXISTS);
        }
        SysUser sysUser = sysUserRepository.findById(userInfo.getUserId()).get();
        sysUser.setUsername(userInfo.getUsername());
        sysUser.setRealName(userInfo.getRealName());
        sysUser.setEnabled(userInfo.getEnabled());
        if(org.apache.commons.lang3.StringUtils.isNotBlank(userInfo.getPassword())) {
            setPassword(sysUser, userInfo.getPassword());
        }
        sysUserRepository.save(sysUser);
    }

    private SysUser setPassword(SysUser sysUser, String password) {
        String salt = "F12839WhsnnEV$#23b";
//        String salt = JwtUtils.generateSalt();
        String pwd = MD5Util.MD5(password + salt);
        sysUser.setSalt(salt);
        sysUser.setPassword(passwordEncoder.encode(password));
        return sysUser;
    }

    private boolean isExistSysUser(String username, String userId){
        return sysUserRepository.findByUsernameAndUserIdNot(username, userId) != null;
    }

    /**
     * remove用户
     *
     * @return
     */
    @Transactional
    public void remove(String userId) {
        sysUserRepository.deleteById(userId);
    }

    public SysUser findSysUserDetail(String usrId) {
        return sysUserRepository.findById(usrId).get();
    }

    /**
     * 获取用户所有角色
     *
     * @return
     */
    public List<SysRole> findSysUserRoles(String userId) {
        List<SysRole> allRoles = sysRoleRepository.findByEnabledTrue();
        SysUser sysUser = sysUserRepository.findById(userId).get();
        return allRoles.stream().map(r -> selectedRole(r, sysUser.getRoleList())).collect(Collectors.toList());
    }

    private SysRole selectedRole(SysRole role, List<SysRole> userRoles) {
        List<SysRole> roles = userRoles.stream().filter(r -> r.getRoleId().equals(role.getRoleId())).collect(Collectors.toList());
        role.setIsSelected(!roles.isEmpty());
        return role;
    }

    /**
     * 分配用户角色
     *
     * @return
     */
    public void allotRole(AllotRole allotRole) {
        List<SysRole> roles = new LinkedList<>();
        if (!allotRole.getRoleIds().isEmpty()) {
            roles = sysRoleRepository.findByRoleIdIn(allotRole.getRoleIds());
        }
        SysUser sysUser = sysUserRepository.findById(allotRole.getUserId()).get();
        sysUser.setRoleList(roles);
        sysUserRepository.save(sysUser);
    }

    /**
     * 修改密码
     *
     * @return
     */
    @Transactional
    public void changePassword(ChangePassword changePassword) {
        Optional<SysUser> optional = this.getCurrentSysUser();
        optional.ifPresent(u -> {
            if (!passwordEncoder.matches(changePassword.getOldPassword(), u.getPassword())) {
                try {
                    throw new BizException(CodeMsg.SYSUSER_OLD_PASSWORD_INVALID.fillArgs(changePassword.getOldPassword()));
                } catch (BizException e) {
                    e.printStackTrace();
                }
            }
            u.setPassword(passwordEncoder.encode(changePassword.getNewPassword()));
            sysUserRepository.save(u);
        });
    }

    public SysUserInfo getCurrentUserInfo() {
        String userId = "";
        SysUser sysUser = sysUserRepository.findById(userId).get();
        List<SysPermission> menus = getSysUserMenus(sysUser);
        List<String> roles = sysUser.getRoleList().stream().map(SysRole::getRoleCode).collect(Collectors.toList());
        return new SysUserInfo(sysUser, menus, roles);
    }

    /**
     * 获取当前用户
     * @return
     */
    private List<SysPermission> getSysUserMenus(SysUser sysUser) {
        List<SysPermission> sysMenus;
        if("admin".equals(sysUser.getUsername())) {
            sysMenus = sysPermissionService.findAllEnableSysMenuList();
        } else {
            Set<SysPermission> menuSet = new HashSet<>();
            for (SysRole role : sysUser.getRoleList()) {
                menuSet.addAll(role.getPermissionList());
            }
            sysMenus = new LinkedList<>(menuSet);
        }
        List<SysPermission> menuList = sysMenus.stream().sorted(Comparator.comparing(SysPermission::getSort)).collect(Collectors.toList());
        return sysPermissionService.menuListToTree(null, menuList);
    }

    /**
     * 获取当前用户
     * @return
     */
    public Optional<SysUser> getCurrentSysUser() {
        String username = SecurityUtils.getCurrentUsername();
        List<SysUser> sysUsers = sysUserRepository.findByUsername(username);
        return sysUsers.isEmpty() ? Optional.empty() : Optional.of(sysUsers.get(0));
    }


    @Transactional
    public void enableUser(String userId) {
        String enableFlag = "1";
        sysUserRepository.setFixedEnableFor(userId,enableFlag);
    }

    @Transactional
    public void disableUser(String userId) {
        String enableFlag = "0";
        sysUserRepository.setFixedEnableFor(userId,enableFlag);
    }
}
